package com.pai4j.aigc.service;

import com.pai4j.aigc.llm.LlmSummarizerService;
import com.pai4j.common.bean.PAIResponseBean;
import com.pai4j.common.bean.PAIResponseBeanUtil;
import com.pai4j.common.enums.ArticleStatusEnum;
import com.pai4j.common.enums.DeleteFlagCodeEnum;
import com.pai4j.common.util.JsonUtil;
import com.pai4j.domain.vo.response.ArticleCardVO;
import com.pai4j.domain.vo.response.subjectaccount.ArticleBaseResponseVO;
import com.pai4j.remote.pgc.SubjectArticleClient;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 智能文章推荐服务
 * 
 * @author PAI4J-AIGC
 * @date 2025-01-26
 */
@Slf4j
@Service
public class ArticleRecommendationService {

    @Resource
    private SubjectArticleClient subjectArticleClient;

    @Resource
    private LlmSummarizerService summarizerService;

    /**
     * 智能推荐文章
     * 
     * @param query 用户问题
     * @param maxResults 最多返回几篇文章（默认3，最大10）
     * @param searchLimit 搜索候选文章数量（默认20，最大50）
     * @return 推荐的文章卡片列表
     */
    public List<ArticleCardVO> recommendArticles(String query, Integer maxResults, Integer searchLimit) {
        // 参数校验与默认值
        if (StringUtils.isBlank(query)) {
            log.warn("推荐文章失败：查询问题为空");
            return Collections.emptyList();
        }
        int resultLimit = maxResults == null || maxResults <= 0 ? 3 : Math.min(maxResults, 10);
        int candidateLimit = searchLimit == null || searchLimit <= 0 ? 20 : Math.min(searchLimit, 50);

        // 1. 从PGC模块获取已发布的文章列表
        PAIResponseBean<com.pai4j.common.bean.PAIPageResponseBeanUtil<ArticleBaseResponseVO>> articlesResp = 
            subjectArticleClient.pageStatus(1, candidateLimit);
        
        if (!PAIResponseBeanUtil.isOk(articlesResp) || articlesResp.getData() == null 
                || CollectionUtils.isEmpty(articlesResp.getData().getData())) {
            log.info("未找到已发布的文章");
            return Collections.emptyList();
        }

        List<ArticleBaseResponseVO> articles = articlesResp.getData().getData();
        log.info("从PGC获取到 {} 篇候选文章", articles.size());

        // 2. 构造候选文章JSON数据
        List<Map<String, Object>> articleMaps = articles.stream().map(article -> {
            Map<String, Object> m = new HashMap<>();
            m.put("articleId", article.getId());
            m.put("title", article.getTitle());
            m.put("description", safeTrim(article.getDescription(), 200));
            m.put("tags", article.getSigns());
            m.put("author", article.getAuthor());
            m.put("publishTime", article.getPublishTime());
            return m;
        }).collect(Collectors.toList());

        // 3. 调用LLM进行智能推荐
        Map<String, Object> vars = new HashMap<>();
        vars.put("query", query);
        vars.put("articleCount", articles.size());
        vars.put("maxResults", resultLimit);
        vars.put("articlesJson", JsonUtil.toJsonString(articleMaps));

        String llmResult = summarizerService.recommendArticles(vars);
        
        if (StringUtils.isBlank(llmResult)) {
            log.warn("LLM推荐结果为空");
            return Collections.emptyList();
        }

        // 4. 解析LLM返回的推荐结果
        List<ArticleCardVO> recommendedCards = parseRecommendations(llmResult, articles);
        
        log.info("成功推荐 {} 篇文章，问题：{}", recommendedCards.size(), query);
        return recommendedCards;
    }

    /**
     * 解析LLM推荐结果并转换为文章卡片
     */
    private List<ArticleCardVO> parseRecommendations(String llmResult, List<ArticleBaseResponseVO> articles) {
        try {
            // 尝试从Markdown代码块中提取JSON
            String jsonStr = extractJsonFromMarkdown(llmResult);
            
            // 解析为列表
            List<Map<String, Object>> recommendations = JsonUtil.fromJson(jsonStr, List.class);
            if (CollectionUtils.isEmpty(recommendations)) {
                return Collections.emptyList();
            }

            // 构建文章ID到文章对象的映射
            Map<Long, ArticleBaseResponseVO> articleMap = articles.stream()
                .collect(Collectors.toMap(ArticleBaseResponseVO::getId, a -> a));

            // 转换为ArticleCardVO
            List<ArticleCardVO> cards = new ArrayList<>();
            for (Map<String, Object> rec : recommendations) {
                Long articleId = getLongValue(rec, "articleId");
                Integer matchScore = getIntValue(rec, "matchScore");
                String recommendReason = getStringValue(rec, "recommendReason");

                ArticleBaseResponseVO article = articleMap.get(articleId);
                if (article == null) {
                    continue;
                }

                ArticleCardVO card = new ArticleCardVO();
                card.setArticleId(articleId);
                card.setTitle(article.getTitle());
                card.setDescription(article.getDescription());
                card.setCoverImage(CollectionUtils.isNotEmpty(article.getCover()) ? article.getCover().get(0) : null);
                card.setAuthorId(article.getAuthor());
                card.setAuthorName(article.getUserInfo() != null ? article.getUserInfo().getUserName() : article.getAuthor());
                card.setTags(article.getSigns());
                card.setMatchScore(matchScore != null ? matchScore : 50);
                card.setJumpUrl("/article/detail/" + articleId);
                card.setPublishTime(article.getPublishTime());
                card.setRecommendReason(recommendReason);
                card.setCardType("ARTICLE");

                cards.add(card);
            }

            return cards;
        } catch (Exception e) {
            log.error("解析LLM推荐结果失败：" + llmResult, e);
            return Collections.emptyList();
        }
    }

    /**
     * 从Markdown代码块中提取JSON
     */
    private String extractJsonFromMarkdown(String text) {
        if (text.contains("```json")) {
            int start = text.indexOf("```json") + 7;
            int end = text.indexOf("```", start);
            if (end > start) {
                return text.substring(start, end).trim();
            }
        } else if (text.contains("```")) {
            int start = text.indexOf("```") + 3;
            int end = text.indexOf("```", start);
            if (end > start) {
                return text.substring(start, end).trim();
            }
        }
        // 如果没有代码块，尝试查找JSON数组
        text = text.trim();
        if (text.startsWith("[") && text.endsWith("]")) {
            return text;
        }
        // 尝试提取第一个[到最后一个]之间的内容
        int start = text.indexOf('[');
        int end = text.lastIndexOf(']');
        if (start >= 0 && end > start) {
            return text.substring(start, end + 1);
        }
        return text;
    }

    private String safeTrim(String s, int maxLen) {
        if (s == null) return "";
        String t = s.replaceAll("\\n", " ").trim();
        if (t.length() > maxLen) t = t.substring(0, maxLen);
        return t;
    }

    private Long getLongValue(Map<String, Object> map, String key) {
        Object val = map.get(key);
        if (val instanceof Number) {
            return ((Number) val).longValue();
        }
        if (val instanceof String) {
            try {
                return Long.parseLong((String) val);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    private Integer getIntValue(Map<String, Object> map, String key) {
        Object val = map.get(key);
        if (val instanceof Number) {
            return ((Number) val).intValue();
        }
        if (val instanceof String) {
            try {
                return Integer.parseInt((String) val);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    private String getStringValue(Map<String, Object> map, String key) {
        Object val = map.get(key);
        return val != null ? val.toString() : "";
    }
}
